<template>
  <div ref="lfElRef" class="logic-container"></div>
  <toolbar :lf="lf" :graph="graph"></toolbar>
  <property-panel
    v-if="lf"
    :lf="lf"
    :context="context"
    @submit="handleSubmit"
  ></property-panel>
</template>

<script name="LogicPanel" lang="ts" setup>
import { onMounted, Ref, ref, unref, defineProps, watch, defineExpose, defineEmits } from 'vue';
import { createApp } from 'vue';

import LogicFlow from "@logicflow/core";
import { Dagre } from "@logicflow/layout";
import { MiniMap, SelectionSelect, Menu } from "@logicflow/extension";

import "@logicflow/core/dist/style/index.css";
import "@logicflow/extension/lib/style/index.css";

import propertyPanel from "../tool/propertyPanel/index.vue";
import insertMenu from "../tool/insertMenu/index.vue";
import toolbar from "../tool/toolbar/index.vue";

import logicLine from "../node/logicLine";
import reaction from "../node/reaction";
import common from "../node/common";
import event from "../node/event";
import { defaultLogo } from "../util/typeMap";

import { waitTime } from "../util/index";
import Graph from "../util/graph";
import { genStartPos, genId } from "../util/calculate";
import { NODE_SPACE_X, NODE_SPACE_Y, EDITOR_EVENT } from "../util/constant";
import { getNodeName } from "../util/node";
import Popover from "../tool/popover/popover";

// 定义挂载元素Ref
const lfElRef: Ref = ref(null);
const lf: Ref = ref(null);
const graph: Ref = ref(null);
const isShowMenu: Ref = ref(false);
const menuPosition: Ref = ref({x: 0, y: 0,});
const currentModel: Ref = ref(null);
const tipText: Ref = ref("");
const loading: Ref = ref(true);

// 定义组件接收的参数
const props = defineProps({
    context: Object,
    info: Object,
});

onMounted(async()=>{
    loading.value = true;
    await waitTime(100);

    initCanvas();
    initEvents();
    initPopover();
    props.info && createDefaultLogic();
    loading.value = false;
});

// 节点拖拽到画布时的操作
const onDrop = (e) => {
  const target = props.context?.Dnd.getDragObject();
  graph.value.addNodeByDrop(target, e);
};

const onDragOver = (e) => {
  e.preventDefault();
};

// 初始化画布
const initCanvas = ()=> {
  const graphData = getGraphDataFromContext();
  lf.value = new LogicFlow({
    container: unref(lfElRef),
    autoExpand: false,
    hoverOutline: false,
    edgeSelectedOutline: false,
    // adjustEdge: false,
    plugins: [MiniMap, SelectionSelect, Menu, Dagre, Popover],
    keyboard: {
      enabled: true,
      shortcuts: [
        {
          keys: "backspace",
          callback: () => {
            const { edges } = lf.value.getSelectElements();
            // 默认只支持删除选中连线
            if (edges && edges.length === 1) {
              lf.value.deleteEdge(edges[0].id);
            }
          },
        },
      ],
    },
    grid: {
      size: 10,
      visible: false,
    },
  });
  lf.value.batchRegister([logicLine, reaction, common, event]);
  lf.value.render(graphData);
  lf.value.setDefaultEdgeType(logicLine.type);
  lf.value.setTheme({
    arrow: {
      offset: 4,
      verticalLength: 3,
    },
    snapline: {
      stroke: "#2961EF", // 对齐线颜色
      strokeWidth: 1, // 对齐线宽度
    },
    bezier: {
      stroke: "#afafaf",
      strokeWidth: 2,
    },
  });

  graph.value = new Graph({
    lf: lf.value,
    context: props.context,
  });

  if (!graphData || graphData.nodes.length === 0){
    graph.value.addInitNode();
  }
    
  graph.value.initView();

  // REMIND: 临时将 lf 挂到 window 方便调试
  window['lf'] = lf;
};

// 初始化事件
const initEvents = () => {
  // Context 事件监听
  // 点击组件时高亮对应节点
  props.context?.eventCenter.on(
    EDITOR_EVENT.CANVAS_MODEL_CLICKED,
    (model) => {
      graph.value.selectNodesByModel(model);
    }
  );
  props.context?.eventCenter.on(
    EDITOR_EVENT.CANVAS_MODEL_DELETED,
    (model) => {
      console.log("EDITOR_EVENT.CANVAS_MODEL_DELETE", model);
      // checkRelatedComponent();
    }
  );

  // LF事件注册
  // 点击处理
  lf.value.on("node:select-click", (model) => {
    graph.value.selectNode(model);
    currentModel.value = model;
  });

  // 属性面板鼠标悬浮到某选项时高亮对应节点
  lf.value.on("node:hover-node", (model) => {
    graph.value.hoverNode(model);
  });

  // 鼠标移出节点后取消画布组件高亮
  lf.value.on("node:mouseleave", () => {
    props.context?.eventCenter.emit(EDITOR_EVENT.LOGIC_NODE_HOVER, null);
  });

  // 监听node点击
  lf.value.on("node:click", ({ data }) => {
    const model = lf.value.getNodeModelById(data.id);
    currentModel.value = model;
  });
  lf.value.on("history:change", () => {
    setGraphDataToContext();
  });
  lf.value.on("node:add-node", ({ model, type, properties }) => {
    graph.value.insertNode(model, type, properties);
  });
  lf.value.on("node:delete-node", (model) => {
    graph.value.deleteNode(model);
    const data = model.getData();
    if (
      data.type === "common-node" &&
      data.properties &&
      data.properties.ds
    ) {
      //checkRelatedNode();
    }
  });
  lf.value.on("node:copy-node", (model) => {
    graph.value.copyNode(model);
  });

  // 如果画布上一个节点都没有了，添加一个引导节点
  lf.value.on("node:delete", ({ data }) => {
    const { nodes } = lf.value.getGraphData();
    if (nodes.length === 0) {
      // 如果当前页面节点都被删除，就自动创建一个页面初始化节点
      graph.value.addInitNode();
    } else if (
      data.properties &&
      data.properties.componentName === "pageInit"
    ) {
      const hasInit = nodes.find(
        (item) =>
          item.properties && item.properties.componentName === "pageInit"
      );
      if (!hasInit) {
        // 如果当前页面没有页面初始化节点了，就自动创建一个
        graph.value.addInitNode();
      }
    }
  });

  // 点击节点添加按钮后，显示添加菜单
  lf.value.on("node:add-click", ({ model, event }) => {
    currentModel.value = model;
    const x = event.clientX;
    const y = event.clientY;
    menuPosition.value = {
      x: x - 10,
      y: y - 10,
    };
    isShowMenu.value = true;
  });
  lf.value.on("edge:update-model", (model) => {
    currentModel.value = model;
  });
  lf.value.on("node:update-model", (model) => {
    currentModel.value = model;
    graph.value.selectNode(model);
  });
  lf.value.on("blank:click", () => {
    currentModel.value = null;
    graph.value.clearNodesStatus();
    props.context?.eventCenter.emit(
      EDITOR_EVENT.CANVAS_MODEL_ACTIVATED,
      null
    );
  });
  lf.value.on("blank:contextmenu", ({ e, position }) => {
    const x = e.clientX;
    const y = e.clientY;
    menuPosition.value = {
      x: x - 10,
      y: y - 10,
    };
    isShowMenu.value = true;
  });
};

// 初始化弹出框
const initPopover = () => {
  const { popover } = lf.value.extension;
  popover.registerPopover("tip1", {
    // TODO: 后续支持传递属性
    render: (rootEl, data) => {
      const vm = createApp({
        render: (h) =>
          h(insertMenu, {
            props: {
              lf: lf,
              context: props.context,
              graph: graph.value,
              model: currentModel.value,
              showConnectBlock: data.props.showConnectBlock,
            },
          }),
      });
      vm.mount(rootEl);
    },
  });
};

/**
 * 从context中获取graphData
 */
const getGraphDataFromContext = () => {
  const { logicList } = props.context;
  if (logicList.length === 1 && logicList[0].nodes !== undefined) {
    // 表示新版数据，目前虽然是一张图，但是以后大概率用多张图来表示逻辑控制，所以先预留数组的形式。
    const graphData = logicList[0];
    graphData.nodes.forEach((node) => {
      const { properties } = node;
      if (properties) {
        node.properties.logo = defaultLogo;
      }
    });
    return graphData;
  }
  return {
    nodes: [],
    edges: [],
  };
};

const setGraphDataToContext = () => {
  const graphData = lf.value.getGraphData();
  graphData.nodes.forEach((node) => {
    if (node.properties) {
      delete node.properties.logo;
      delete node.properties.status;
      delete node.properties.warnings;
    }
  });
  props.context.logicList = [graphData];
};

/**
 * 获取节点的outgoing
 * outgoing: [
 *  {
 *    id: 'edgeId',
 *    condition: 'nodeId_1.eventType === "click"',
 *    text: '点击',
 *    target: 'nodeId_2',
 *    pointsList: [] // 连线的坐标
 *  }
 * ]
 */
const getNodeOutgoing = (nodeId) => {
  const edges = lf.value.getNodeOutgoingEdge(nodeId);
  return edges.map((edgeModel) => {
    const edgeData = edgeModel.getData();
    return {
      id: edgeData.id,
      condition: edgeData.properties.condition,
      text: edgeData.text ? edgeData.text.value : "",
      target: edgeData.targetNodeId,
      pointsList: edgeData.pointsList,
    };
  });
};

const handleSubmit = (type) => {
  if (type === "ds") {
    //checkRelatedDs();
  }
  graph.value.addHistory();
};

/**
 * 根据传入的model创建行为节点、引导
 */
const createDefaultNode = (startPos) => {
  const { dynamicKey, model } = props.info;
  const logic = model.getLogic();
  const logicProps = logic.props || [];
  const currentProp = logicProps.find((item) => item.name === dynamicKey) || {};
  const actNode = {
    id: genId(10, null),
    type: reaction.type,
    x: startPos.x + NODE_SPACE_X * 2,
    y: startPos.y,
    properties: {
      componentId: model.id,
      componentName: model.componentName,
      name: getNodeName(model),
      reactions: [
        {
          key: dynamicKey,
          keyDefine: currentProp.description,
          valueDefine: "",
          value: {
            type: "dataSource",
          },
        },
      ],
      item: {
        prop: true,
      },
    },
  };
  return actNode;
};

/**
 * 在setter点击动态数据设置后，跳转到逻辑编排并自动创建一条逻辑
 */
const createDefaultLogic = () => {
  const startPos = genStartPos(lf.value);
  const startNode = {
    id: genId(10, null),
    type: event.type,
    x: startPos.x,
    y: startPos.y,
    properties: {
      componentId: "page_init",
      componentName: "pageInit",
      name: "页面初始化",
    },
  };
  const reqNode = {
    id: genId(10, null),
    type: common.type,
    x: startPos.x + NODE_SPACE_X,
    y: startPos.y,
    properties: {
      type: "dataSource",
      componentName: "dataSource",
      name: "数据请求",
    },
  };
  const actNode = createDefaultNode(startPos);
  const graphData = {
    nodes: [startNode, reqNode, actNode],
    edges: [
      {
        id: genId(10, null),
        type: logicLine.type,
        sourceNodeId: startNode.id,
        targetNodeId: reqNode.id,
      },
      {
        id: genId(10, null),
        type: logicLine.type,
        sourceNodeId: reqNode.id,
        targetNodeId: actNode.id,
      },
    ],
  };
  lf.value.addElements(graphData);
  lf.value.translate(0, -NODE_SPACE_Y);
}

</script>

<style scoped lang="less">
.system-warning {
  position: absolute;
  right: 0;
  bottom: 0;
  color: orange;
  background: #fff;
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  box-shadow: 0 2px 12px 0 rgb(31 50 82 / 18%);
  border-radius: 2px;
  padding: 12px;
  font-size: 14px;
}
.logic-panel,
.logic-container {
  width: 100%;
  height: 100%;
  position: relative;
}
.logic-palette {
  position: absolute;
  left: 0;
  top: 0;
}

/*自定义锚点样式*/
.logic-panel {
  :deep(.custom-anchor) {
    stroke: #2961ef;
    stroke-width: 1;
    fill: #fff;
    cursor: crosshair;
    rx: 3;
    ry: 3;
  }
  :deep(.custom-anchor:hover) {
    stroke: #2961ef;
    stroke-width: 1;
    fill: #fff;
  }
  :deep(.lf-node-not-allow .custom-anchor:hover) {
    stroke: #999;
    fill: #d9d9d9;
    cursor: not-allowed;
  }
  :deep(.incomming-anchor) {
    stroke: #2961ef;
    cursor: default;
  }
  :deep(.outgoing-anchor)  {
    stroke: #2961ef;
  }
  :deep(.lf-node-not-allow .basic-node) {
    cursor: not-allowed;
  }
  :deep(.lf-control-item i) {
    font-size: 20px;
    font-weight: 600;
  }
  :deep(.lf-multiple-select) {
    background: rgba(224, 80, 10, 0.2);
  }
  :deep(.lf-grid > svg) {
    background-image: url("../../../../assets/svg/grid.svg");
    background-size: 50px 50px;
    background-repeat: repeat;
  }
}
</style>
